<!DOCTYPE html>
<html lang="zh-CN" class="scroll-smooth">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>激光位移传感器测量系统</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/dist/tabler-icons.min.css" rel="stylesheet"/>
  <script>
    tailwind.config = {
      darkMode: 'class',
      theme: {
        extend: {
          colors: {
            primary: '#3b82f6',
            'primary-dark': '#2563eb',
            'gray-light': '#f3f4f6',
            'gray-dark': '#1f2937',
          }
        }
      }
    };
  </script>
  <style>
    @keyframes fadeInUp {
      from { opacity: 0; transform: translateY(20px); }
      to { opacity: 1; transform: translateY(0); }
    }
    .animate-fade-in-up { animation: fadeInUp 0.6s ease-out forwards; }
    .card-hover-effect { transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); }
    .card-hover-effect:hover { @apply shadow-xl scale-[1.02] border-primary; }
    .btn-hover-effect { transition: all 0.2s ease; }
    .btn-hover-effect:hover { @apply scale-105 brightness-110; }
    .status-badge { @apply inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium; }
    .pulse-animation { animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; }
    @keyframes pulse {
      0%, 100% { opacity: 1; }
      50% { opacity: 0.7; }
    }
  </style>
</head>
<body class="bg-gray-light text-gray-800 dark:bg-gray-dark dark:text-gray-200 min-h-screen font-sans antialiased transition-colors duration-300">

<header class="bg-white dark:bg-gray-900 shadow-sm border-b border-gray-200 dark:border-gray-700 sticky top-0 z-50 backdrop-blur-lg bg-opacity-90 dark:bg-opacity-90">
  <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 flex justify-between items-center">
    <div class="flex items-center space-x-3">
      <div class="text-primary dark:text-primary-dark">
        <svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
          <path d="M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83M7 12a5 5 0 1110 0 5 5 0 01-10 0z"/>
        </svg>
      </div>
      <h1 class="text-2xl font-bold"><span class="text-primary dark:text-primary-dark">激光位移传感器测量</span> 控制平台</h1>
    </div>
    <button id="theme-toggle" aria-label="切换主题" class="p-2 rounded-full hover:bg-gray-200 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-primary">
      <span id="light-icon" class="ti ti-sun hidden"></span>
      <span id="dark-icon" class="ti ti-moon"></span>
    </button>
  </div>
</header>

<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">

  <!-- 状态概览 -->
  <section class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8 animate-fade-in-up">
    <div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow-md card-hover-effect border border-transparent transition-colors duration-300">
      <div class="flex items-center justify-between">
        <div>
          <p class="text-sm font-medium text-gray-600 dark:text-gray-300">系统状态</p>
          <p id="system-status" class="text-lg font-semibold text-gray-800 dark:text-gray-100 mt-1">未连接</p>
          <span id="status-badge" class="status-badge bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300 mt-2">未就绪</span>
        </div>
        <div class="p-3 rounded-full bg-blue-100 dark:bg-blue-900 text-primary dark:text-primary-dark">
          <span class="ti ti-gauge ti-lg"></span>
        </div>
      </div>
    </div>

    <div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow-md card-hover-effect border border-transparent transition-colors duration-300">
      <div class="flex items-center justify-between">
        <div>
          <p class="text-sm font-medium text-gray-600 dark:text-gray-300">采集模式</p>
          <p id="measure-mode" class="text-lg font-semibold text-gray-800 dark:text-gray-100 mt-1">连续旋转</p>
          <p id="angle-step-display" class="text-xs text-gray-500 dark:text-gray-400 mt-2">角度间隔：-- 度</p>
        </div>
        <div class="p-3 rounded-full bg-purple-100 dark:bg-purple-900 text-purple-600 dark:text-purple-300">
          <span class="ti ti-mode ti-lg"></span>
        </div>
      </div>
    </div>

    <div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow-md card-hover-effect border border-transparent transition-colors duration-300">
      <div class="flex items-center justify-between">
        <div>
          <p class="text-sm font-medium text-gray-600 dark:text-gray-300">累积移动距离</p>
          <p id="total-distance" class="text-lg font-semibold text-gray-800 dark:text-gray-100 mt-1">0.0 mm</p>
          <p class="text-xs text-gray-500 dark:text-gray-400 mt-2">导程：5mm/圈</p>
        </div>
        <div class="p-3 rounded-full bg-green-100 dark:bg-green-900 text-green-600 dark:text-green-300">
          <span class="ti ti-ruler-horizontal ti-lg"></span>
        </div>
      </div>
    </div>

    <div class="bg-white dark:bg-gray-800 p-6 rounded-xl shadow-md card-hover-effect border border-transparent transition-colors duration-300">
      <div class="flex items-center justify-between">
        <div>
          <p class="text-sm font-medium text-gray-600 dark:text-gray-300">实时测量值</p>
          <p id="real-distance" class="text-lg font-semibold text-gray-800 dark:text-gray-100 mt-1">--.----- mm</p>
          <p id="real-angle" class="text-xs text-gray-500 dark:text-gray-400 mt-2">角度：--.---- °</p>
        </div>
        <div class="p-3 rounded-full bg-orange-100 dark:bg-orange-900 text-orange-600 dark:text-orange-300">
          <span class="ti ti-ruler-2 ti-lg"></span>
        </div>
      </div>
    </div>
  </section>

  <!-- 采集模式配置 -->
  <section class="bg-white dark:bg-gray-800 rounded-xl shadow-md p-6 mb-8 card-hover-effect border border-transparent transition-colors duration-300 animate-fade-in-up" style="animation-delay: 0.1s">
    <h2 class="text-xl font-semibold mb-6 flex items-center">
      <span class="ti ti-settings mr-2 text-primary"></span>
      采集模式配置
    </h2>
    <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
      <!-- 模式选择 -->
      <div>
        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">选择采集模式</label>
        <div class="flex space-x-4">
          <label class="inline-flex items-center">
            <input type="radio" name="measure-mode" value="continuous" checked class="form-radio text-primary focus:ring-primary">
            <span class="ml-2">连续旋转采集</span>
          </label>
          <label class="inline-flex items-center">
            <input type="radio" name="measure-mode" value="fixed_angle" class="form-radio text-primary focus:ring-primary">
            <span class="ml-2">定点角度采集</span>
          </label>
        </div>
      </div>
      <!-- 角度间隔设置 -->
      <div id="angle-step-config" class="hidden">
        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">定点角度间隔（度）</label>
        <div class="flex items-center space-x-2">
          <input type="number" id="angle-step" min="1" max="180" value="10" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary focus:border-primary dark:bg-gray-700 dark:text-white">
          <button id="save-mode" class="btn-hover-effect bg-primary hover:bg-primary-dark text-white py-2 px-4 rounded-lg font-medium transition-colors duration-200">
            保存配置
          </button>
        </div>
        <p class="text-xs text-gray-500 dark:text-gray-400 mt-1">提示：角度间隔需为1-180之间的整数，间隔越小采集点越密集</p>
      </div>
    </div>
  </section>

  <!-- 控制操作区 -->
  <section class="bg-white dark:bg-gray-800 rounded-xl shadow-md p-6 mb-8 card-hover-effect border border-transparent transition-colors duration-300 animate-fade-in-up" style="animation-delay: 0.2s">
    <h2 class="text-xl font-semibold mb-6 flex items-center">
      <span class="ti ti-player-play-filled mr-2 text-primary"></span>
      设备控制
    </h2>
    <div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-5 gap-4">
      <button id="btn-start" class="btn-hover-effect bg-primary hover:bg-primary-dark text-white py-3 px-4 rounded-lg font-medium transition-all duration-200 flex flex-col items-center justify-center shadow-md hover:shadow-lg disabled:opacity-70 disabled:cursor-not-allowed disabled:scale-100" disabled>
        <span class="ti ti-playstation-square ti-lg mb-1"></span>
        开始测量
      </button>
      <button id="btn-stop" class="btn-hover-effect bg-yellow-500 hover:bg-yellow-600 text-white py-3 px-4 rounded-lg font-medium transition-all duration-200 flex flex-col items-center justify-center shadow-md hover:shadow-lg disabled:opacity-70 disabled:cursor-not-allowed disabled:scale-100" disabled>
        <span class="ti ti-player-pause-filled ti-lg mb-1"></span>
        停止测量
      </button>
      <button id="btn-reset" class="btn-hover-effect bg-indigo-500 hover:bg-indigo-600 text-white py-3 px-4 rounded-lg font-medium transition-all duration-200 flex flex-col items-center justify-center shadow-md hover:shadow-lg disabled:opacity-70 disabled:cursor-not-allowed disabled:scale-100" disabled>
        <span class="ti ti-refresh ti-lg mb-1"></span>
        复位系统
      </button>
      <button id="btn-export" class="btn-hover-effect bg-green-500 hover:bg-green-600 text-white py-3 px-4 rounded-lg font-medium transition-all duration-200 flex flex-col items-center justify-center shadow-md hover:shadow-lg disabled:opacity-70 disabled:cursor-not-allowed disabled:scale-100" disabled>
        <span class="ti ti-download ti-lg mb-1"></span>
        导出数据
      </button>
      <button id="btn-emergency" class="btn-hover-effect bg-red-500 hover:bg-red-600 text-white py-3 px-4 rounded-lg font-medium transition-all duration-200 flex flex-col items-center justify-center shadow-md hover:shadow-lg disabled:opacity-70 disabled:cursor-not-allowed disabled:scale-100" disabled>
        <span class="ti ti-exclamation-circle ti-lg mb-1"></span>
        紧急停止
      </button>
    </div>
  </section>

  <!-- 参数设置按钮 -->
  <section class="mb-8 animate-fade-in-up" style="animation-delay: 0.3s">
    <button id="btn-settings" class="btn-hover-effect bg-indigo-500 hover:bg-indigo-600 text-white py-2 px-6 rounded-lg font-medium transition-all duration-200 flex items-center shadow-md hover:shadow-lg">
      <span class="ti ti-settings ti-lg mr-2"></span>
      参数设置
    </button>
  </section>

  <!-- 实时数据图表 -->
  <section class="bg-white dark:bg-gray-800 rounded-xl shadow-md p-6 mb-8 card-hover-effect border border-transparent transition-colors duration-300 animate-fade-in-up" style="animation-delay: 0.4s">
    <h2 class="text-xl font-semibold mb-6 flex items-center">
      <span class="ti ti-chart-line ti-lg mr-2 text-primary"></span>
      实时测量数据
    </h2>
    <div class="relative h-80 w-full bg-gray-50 dark:bg-gray-900 rounded-lg overflow-hidden">
      <canvas id="data-chart" class="absolute inset-0 w-full h-full"></canvas>
      <div id="chart-placeholder" class="absolute inset-0 flex items-center justify-center text-gray-500 dark:text-gray-400">
        <div class="text-center">
          <span class="ti ti-chart-line ti-4x opacity-50"></span>
          <p class="mt-2">请先连接设备并开始测量...</p>
        </div>
      </div>
    </div>
  </section>

  <!-- 数据详情表格 -->
  <section class="bg-white dark:bg-gray-800 rounded-xl shadow-md p-6 animate-fade-in-up" style="animation-delay: 0.5s">
    <h2 class="text-xl font-semibold mb-6 flex items-center">
      <span class="ti ti-table ti-lg mr-2 text-primary"></span>
      测量数据详情
    </h2>
    <div class="overflow-x-auto">
      <table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
        <thead class="bg-gray-50 dark:bg-gray-800">
          <tr>
            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">测量时间</th>
            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">移动距离(mm)</th>
            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">旋转角度(°)</th>
            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">测量值(mm)</th>
            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">采集模式</th>
          </tr>
        </thead>
        <tbody id="data-table-body" class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
          <tr>
            <td colspan="5" class="px-6 py-10 text-center text-gray-500 dark:text-gray-400">
              暂无测量数据
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </section>

</main>

<footer class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6 text-center text-sm text-gray-500 dark:text-gray-400">
  激光位移传感器测量系统 © <span id="year">2025</span> | 数据保存路径：<span id="csv-path">未生成</span>
</footer>

<!-- 参数设置模态框 -->
<div id="settings-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
  <div class="bg-white dark:bg-gray-800 rounded-xl shadow-xl w-full max-w-2xl max-h-[90vh] overflow-y-auto">
    <div class="p-6 border-b border-gray-200 dark:border-gray-700">
      <div class="flex justify-between items-center">
        <h3 class="text-lg font-semibold">设备参数设置</h3>
        <button id="close-modal" class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
          <span class="ti ti-x ti-lg"></span>
        </button>
      </div>
    </div>
    <div class="p-6">
      <form id="settings-form">
        <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
          <div>
            <label for="port" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">串口端口</label>
            <input type="text" id="port" value="COM3" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary focus:border-primary dark:bg-gray-700 dark:text-white">
          </div>
          <div>
            <label for="baudrate" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">波特率</label>
            <input type="number" id="baudrate" value="115200" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary focus:border-primary dark:bg-gray-700 dark:text-white">
          </div>
          <div>
            <label for="stepper-cycles" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">步进电机循环次数</label>
            <input type="number" id="stepper-cycles" min="1" value="2" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary focus:border-primary dark:bg-gray-700 dark:text-white">
          </div>
          <div>
            <label for="repeat-times" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">测量重复次数</label>
            <input type="number" id="repeat-times" min="1" value="50" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary focus:border-primary dark:bg-gray-700 dark:text-white">
          </div>
          <div>
            <label for="sample-interval" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">采样间隔(秒)</label>
            <input type="number" id="sample-interval" min="0.01" step="0.01" value="0.05" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary focus:border-primary dark:bg-gray-700 dark:text-white">
          </div>
          <div>
            <label for="switch-mode" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">传感器切换模式</label>
            <select id="switch-mode" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary focus:border-primary dark:bg-gray-700 dark:text-white">
              <option value="distance">按距离</option>
              <option value="value">按测量值</option>
            </select>
          </div>
        </div>
        <div class="mt-6 flex space-x-4">
          <button type="submit" class="flex-1 bg-primary hover:bg-primary-dark text-white py-2 px-4 rounded-lg font-medium transition-colors duration-200">保存并连接</button>
          <button type="button" id="close-modal-btn" class="flex-1 bg-gray-300 hover:bg-gray-400 dark:bg-gray-600 dark:hover:bg-gray-500 text-gray-800 dark:text-white py-2 px-4 rounded-lg font-medium transition-colors duration-200">取消</button>
        </div>
      </form>
    </div>
  </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
  document.getElementById('year').textContent = new Date().getFullYear();

  // 1. 主题切换逻辑
  const themeToggle = document.getElementById('theme-toggle');
  const lightIcon = document.getElementById('light-icon');
  const darkIcon = document.getElementById('dark-icon');
  const savedTheme = localStorage.getItem('theme') || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
  
  if (savedTheme === 'dark') {
    document.documentElement.classList.add('dark');
    lightIcon.classList.add('hidden');
    darkIcon.classList.remove('hidden');
  } else {
    document.documentElement.classList.remove('dark');
    lightIcon.classList.remove('hidden');
    darkIcon.classList.add('hidden');
  }
  
  themeToggle.addEventListener('click', () => {
    if (document.documentElement.classList.contains('dark')) {
      document.documentElement.classList.remove('dark');
      localStorage.setItem('theme', 'light');
      lightIcon.classList.remove('hidden');
      darkIcon.classList.add('hidden');
    } else {
      document.documentElement.classList.add('dark');
      localStorage.setItem('theme', 'dark');
      lightIcon.classList.add('hidden');
      darkIcon.classList.remove('hidden');
    }
  });

  // 2. API接口定义
  const API = {
    connect: (config) => fetch('http://localhost:5000/api/connect', { 
      method: 'POST', 
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(config)
    }).then(r => r.json()),
    setMode: (data) => fetch('http://localhost:5000/api/set-mode', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data)
    }).then(r => r.json()),
    startMeasure: () => fetch('http://localhost:5000/api/start', { method: 'POST' }).then(r => r.json()),
    stopMeasure: () => fetch('http://localhost:5000/api/stop', { method: 'POST' }).then(r => r.json()),
    emergencyStop: () => fetch('http://localhost:5000/api/emergency', { method: 'POST' }).then(r => r.json()),
    resetSystem: () => fetch('http://localhost:5000/api/reset', { method: 'POST' }).then(r => r.json()),
    getStatus: () => fetch('http://localhost:5000/api/status').then(r => r.json()),
    getConfig: () => fetch('http://localhost:5000/api/config').then(r => r.json()),
    exportData: () => fetch('http://localhost:5000/api/export', { method: 'POST' })
  };

  // 3. 页面状态管理
  let chart = null;
  let statusPollingInterval = null;
  let dataTableMaxRows = 20; // 表格最大显示行数

  // 4. 初始化图表
  function initChart() {
    const ctx = document.getElementById('data-chart').getContext('2d');
    chart = new Chart(ctx, {
      type: 'line',
      data: {
        datasets: [{
          label: '激光测量距离 (mm)',
          data: [],
          borderColor: '#3b82f6',
          backgroundColor: 'rgba(59, 130, 246, 0.1)',
          borderWidth: 2,
          pointRadius: 2,
          pointHoverRadius: 5,
          fill: true,
          tension: 0.3,
          order: 1
        }]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: {
          legend: {
            position: 'top',
            labels: {
              color: document.documentElement.classList.contains('dark') ? '#e5e7eb' : '#4b5563'
            }
          },
          tooltip: {
            mode: 'index',
            intersect: false,
            backgroundColor: 'rgba(0,0,0,0.8)',
            titleColor: '#fff',
            bodyColor: '#fff'
          }
        },
        scales: {
          x: {
            display: true,
            title: {
              display: true,
              text: '云台旋转角度 (°)',
              color: document.documentElement.classList.contains('dark') ? '#9ca3af' : '#6b7280',
              font: { size: 12 }
            },
            ticks: { 
              color: document.documentElement.classList.contains('dark') ? '#9ca3af' : '#6b7280',
              autoSkip: true,
              maxTicksLimit: 10
            },
            grid: { 
              color: document.documentElement.classList.contains('dark') ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.05)',
              drawBorder: false 
            }
          },
          y: {
            display: true,
            title: {
              display: true,
              text: '距离 (mm)',
              color: document.documentElement.classList.contains('dark') ? '#9ca3af' : '#6b7280',
              font: { size: 12 }
            },
            ticks: { color: document.documentElement.classList.contains('dark') ? '#9ca3af' : '#6b7280' },
            grid: { 
              color: document.documentElement.classList.contains('dark') ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.05)',
              drawBorder: false 
            }
          }
        },
        interaction: {
          mode: 'nearest',
          axis: 'x',
          intersect: false
        },
        animation: {
          duration: 0 // 关闭动画，提升实时性
        }
      }
    });
  }

  // 5. 更新系统状态显示
  function updateSystemStatus(status) {
    // 状态文本更新
    const statusEl = document.getElementById('system-status');
    const statusBadge = document.getElementById('status-badge');
    const measureModeEl = document.getElementById('measure-mode');
    const angleStepEl = document.getElementById('angle-step-display');
    const totalDistanceEl = document.getElementById('total-distance');
    const realDistanceEl = document.getElementById('real-distance');
    const realAngleEl = document.getElementById('real-angle');
    const csvPathEl = document.getElementById('csv-path');

    // 基础状态更新
    statusEl.textContent = status.system_status || '未知';
    measureModeEl.textContent = status.measure_mode === 'continuous' ? '连续旋转' : '定点角度';
    angleStepEl.textContent = status.measure_mode === 'fixed_angle' ? `角度间隔：${status.angle_step} 度` : '角度间隔：-- 度';
    totalDistanceEl.textContent = status.total_move_distance ? `${status.total_move_distance.toFixed(1)} mm` : '0.0 mm';
    realDistanceEl.textContent = status.current_distance !== null ? `${status.current_distance.toFixed(5)} mm` : '--.----- mm';
    realAngleEl.textContent = status.current_angle !== null ? `角度：${status.current_angle.toFixed(4)} °` : '角度：--.---- °';
    csvPathEl.textContent = status.csv_file ? status.csv_file.split('/').pop() : '未生成';

    // 状态徽章样式更新
    if (status.system_status === '已连接') {
      statusBadge.className = 'status-badge bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300 mt-2';
      statusBadge.textContent = '就绪';
    } else if (status.system_status === '测量中') {
      statusBadge.className = 'status-badge bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300 mt-2 pulse-animation';
      statusBadge.textContent = '测量中';
    } else if (status.system_status === '测量完成') {
      statusBadge.className = 'status-badge bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300 mt-2';
      statusBadge.textContent = '已完成';
    } else if (status.system_status === '待机') {
      statusBadge.className = 'status-badge bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300 mt-2';
      statusBadge.textContent = '待机';
    } else {
      statusBadge.className = 'status-badge bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300 mt-2';
      statusBadge.textContent = '未就绪';
    }

    // 按钮状态控制
    const btnStart = document.getElementById('btn-start');
    const btnStop = document.getElementById('btn-stop');
    const btnReset = document.getElementById('btn-reset');
    const btnExport = document.getElementById('btn-export');
    const btnEmergency = document.getElementById('btn-emergency');
    const btnSettings = document.getElementById('btn-settings');

    // 根据连接状态控制按钮
    const isConnected = ['已连接', '测量中', '待机', '测量完成'].includes(status.system_status);
    btnSettings.disabled = status.system_status === '测量中';
    btnReset.disabled = !isConnected;
    btnEmergency.disabled = !isConnected;

    // 测量状态控制
    if (status.system_status === '测量中') {
      btnStart.disabled = true;
      btnStop.disabled = false;
      btnExport.disabled = true;
    } else {
      btnStart.disabled = !(status.system_status === '已连接' || status.system_status === '待机' || status.system_status === '测量完成');
      btnStop.disabled = true;
      btnExport.disabled = (status.data && status.data.length || 0) === 0;
    }

    // 导出按钮样式调整
    if (!btnExport.disabled) {
      btnExport.classList.remove('opacity-70', 'cursor-not-allowed');
    } else {
      btnExport.classList.add('opacity-70', 'cursor-not-allowed');
    }

    // 实时图表更新（仅测量中状态）
    if (status.is_measuring && status.current_angle !== null && status.current_distance !== null) {
      updateChart(status.current_angle, status.current_distance);
    }

    // 数据表格更新
    if (status.data && status.data.length > 0) {
      updateDataTable(status.data);
    }
  }

  // 6. 更新图表数据
  function updateChart(angle, distance) {
    if (!chart) return;

    const dataset = chart.data.datasets[0];
    const lastPoint = dataset.data[dataset.data.length - 1];
    
    // 避免添加过于接近的角度点（优化性能）
    if (!lastPoint || Math.abs(lastPoint.x - angle) > 0.1) {
      dataset.data.push({ x: angle, y: distance });
      
      // 限制数据点数量（最多500个）
      if (dataset.data.length > 500) {
        dataset.data.shift();
      }
      
      chart.update();
      document.getElementById('chart-placeholder').classList.add('hidden');
    }
  }

  // 7. 更新数据表格
  function updateDataTable(data) {
    const tableBody = document.getElementById('data-table-body');
    tableBody.innerHTML = '';

    // 取最新的N条数据（倒序）
    const displayData = data.slice(-dataTableMaxRows).reverse();

    displayData.forEach(row => {
      const tr = document.createElement('tr');
      tr.className = 'hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors';
      
      // 测量时间
      const timeTd = document.createElement('td');
      timeTd.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-300';
      timeTd.textContent = row[0];
      tr.appendChild(timeTd);

      // 移动距离
      const moveTd = document.createElement('td');
      moveTd.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100';
      moveTd.textContent = row[1].toFixed(1);
      tr.appendChild(moveTd);

      // 旋转角度
      const angleTd = document.createElement('td');
      angleTd.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100';
      angleTd.textContent = row[2].toFixed(4);
      tr.appendChild(angleTd);

      // 测量值
      const distanceTd = document.createElement('td');
      distanceTd.className = 'px-6 py-4 whitespace-nowrap text-sm font-medium text-primary';
      distanceTd.textContent = row[3].toFixed(5);
      tr.appendChild(distanceTd);

      // 采集模式
      const modeTd = document.createElement('td');
      modeTd.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-300';
      modeTd.textContent = row[4] || '未知';
      tr.appendChild(modeTd);

      tableBody.appendChild(tr);
    });
  }

  // 8. 初始化事件监听
  function initEventListeners() {
    // 8.1 模式选择切换
    const measureModeRadios = document.querySelectorAll('input[name="measure-mode"]');
    const angleStepConfig = document.getElementById('angle-step-config');
    
    measureModeRadios.forEach(radio => {
      radio.addEventListener('change', () => {
        // 切换角度间隔配置显示
        angleStepConfig.classList.toggle('hidden', radio.value !== 'fixed_angle');
      });
    });

    // 8.2 保存采集模式配置
    document.getElementById('save-mode').addEventListener('click', () => {
      const selectedMode = document.querySelector('input[name="measure-mode"]:checked').value;
      const configData = { measure_mode: selectedMode };

      // 定点模式需添加角度间隔
      if (selectedMode === 'fixed_angle') {
        const angleStep = parseInt(document.getElementById('angle-step').value);
        if (isNaN(angleStep) || angleStep < 1 || angleStep > 180) {
          alert('角度间隔必须为1-180之间的整数！');
          return;
        }
        configData.angle_step = angleStep;
      }

      // 发送配置到后端
      API.setMode(configData)
        .then(resp => {
          if (resp.status === 'success') {
            alert(`配置成功！当前模式：${selectedMode === 'continuous' ? '连续旋转采集' : `定点角度采集（间隔${configData.angle_step}度）`}`);
          } else {
            alert(`配置失败：${resp.message}`);
          }
        })
        .catch(err => {
          alert(`配置请求失败：${err.message}`);
        });
    });

    // 8.3 开始测量
    document.getElementById('btn-start').addEventListener('click', () => {
      if (confirm('确定要开始测量吗？')) {
        API.startMeasure()
          .then(resp => {
            if (resp.status !== 'success') {
              alert(`启动失败：${resp.message}`);
            }
          })
          .catch(err => {
            alert(`启动请求失败：${err.message}`);
          });
      }
    });

    // 8.4 停止测量
    document.getElementById('btn-stop').addEventListener('click', () => {
      if (confirm('确定要停止测量吗？')) {
        API.stopMeasure()
          .then(resp => {
            if (resp.status !== 'success') {
              alert(`停止失败：${resp.message}`);
            }
          })
          .catch(err => {
            alert(`停止请求失败：${err.message}`);
          });
      }
    });

    // 8.5 紧急停止
    document.getElementById('btn-emergency').addEventListener('click', () => {
      if (confirm('确定要执行紧急停止吗？这将立即中断所有操作！')) {
        API.emergencyStop()
          .then(resp => {
            if (resp.status !== 'success') {
              alert(`紧急停止失败：${resp.message}`);
            } else {
              alert('紧急停止已执行');
            }
          })
          .catch(err => {
            alert(`紧急停止请求失败：${err.message}`);
          });
      }
    });

    // 8.6 复位系统
    document.getElementById('btn-reset').addEventListener('click', () => {
      if (confirm('确定要复位系统吗？这将重置当前状态和数据！')) {
        // 清除图表数据
        if (chart) {
          chart.data.datasets[0].data = [];
          chart.update();
          document.getElementById('chart-placeholder').classList.remove('hidden');
        }
        document.getElementById('data-table-body').innerHTML = `
          <tr>
            <td colspan="5" class="px-6 py-10 text-center text-gray-500 dark:text-gray-400">
              暂无测量数据
            </td>
          </tr>
        `;
        API.resetSystem()
          .then(resp => {
            if (resp.status !== 'success') {
              alert(`复位失败：${resp.message}`);
            } else {
              alert('系统已复位');
            }
          })
          .catch(err => {
            alert(`复位请求失败：${err.message}`);
          });
      }
    });

    // 8.7 参数设置模态框
    const settingsModal = document.getElementById('settings-modal');
    document.getElementById('btn-settings').addEventListener('click', () => {
      settingsModal.classList.remove('hidden');
    });

    // 关闭模态框
    document.getElementById('close-modal').addEventListener('click', () => {
      settingsModal.classList.add('hidden');
    });
    document.getElementById('close-modal-btn').addEventListener('click', () => {
      settingsModal.classList.add('hidden');
    });

    // 点击模态框外部关闭
    settingsModal.addEventListener('click', (e) => {
      if (e.target === settingsModal) {
        settingsModal.classList.add('hidden');
      }
    });

    // 8.8 保存参数设置并连接
    document.getElementById('settings-form').addEventListener('submit', (e) => {
      e.preventDefault();
      
      const config = {
        port: document.getElementById('port').value,
        baudrate: parseInt(document.getElementById('baudrate').value),
        stepper_cycles: parseInt(document.getElementById('stepper-cycles').value),
        repeat_times: parseInt(document.getElementById('repeat-times').value),
        sample_interval: parseFloat(document.getElementById('sample-interval').value),
        switch_mode: document.getElementById('switch-mode').value
      };

      // 验证配置
      if (isNaN(config.baudrate) || config.baudrate <= 0) {
        alert('请输入有效的波特率');
        return;
      }
      if (isNaN(config.stepper_cycles) || config.stepper_cycles < 1) {
        alert('步进电机循环次数必须大于0');
        return;
      }
      if (isNaN(config.repeat_times) || config.repeat_times < 1) {
        alert('测量重复次数必须大于0');
        return;
      }
      if (isNaN(config.sample_interval) || config.sample_interval < 0.01) {
        alert('采样间隔必须大于等于0.01秒');
        return;
      }

      // 发送连接请求
      API.connect(config)
        .then(resp => {
          if (resp.status === 'success') {
            alert('设备连接成功！');
            settingsModal.classList.add('hidden');
          } else {
            alert(`连接失败：${resp.message}`);
          }
        })
        .catch(err => {
          alert(`连接请求失败：${err.message}`);
        });
    });

    // 8.9 导出CSV按钮
    document.getElementById('btn-export').addEventListener('click', () => {
      API.exportData()
        .then(resp => {
          if (!resp.ok) {
            throw new Error('导出请求失败');
          }
          return resp.blob();
        })
        .then(blob => {
          // 创建下载链接
          const url = window.URL.createObjectURL(blob);
          const a = document.createElement('a');
          a.href = url;
          a.download = `测量结果_${new Date().toISOString().slice(0,19).replace(/:/g,'-')}.csv`;
          document.body.appendChild(a);
          a.click();
          // 清理资源
          window.URL.revokeObjectURL(url);
          document.body.removeChild(a);
          alert('数据导出成功！');
        })
        .catch(err => {
          alert(`导出失败：${err.message}`);
        });
    });

    // 8.10 加载初始配置
    API.getConfig()
      .then(resp => {
        if (resp.status === 'success') {
          const config = resp.config;
          // 填充表单
          document.getElementById('port').value = config.port || 'COM3';
          document.getElementById('baudrate').value = config.baudrate || 115200;
          document.getElementById('stepper-cycles').value = config.stepper_cycles || 2;
          document.getElementById('repeat-times').value = config.repeat_times || 50;
          document.getElementById('sample-interval').value = config.sample_interval || 0.05;
          document.getElementById('switch-mode').value = config.switch_mode || 'distance';
          // 选中当前采集模式
          const modeRadio = document.querySelector(`input[name="measure-mode"][value="${config.measure_mode || 'continuous'}"]`);
          if (modeRadio) modeRadio.checked = true;
          // 显示角度间隔配置（如果是定点模式）
          if (config.measure_mode === 'fixed_angle') {
            angleStepConfig.classList.remove('hidden');
            document.getElementById('angle-step').value = config.angle_step || 10;
          }
        }
      })
      .catch(err => {
        console.error('加载初始配置失败:', err);
      });
  }

  // 9. 启动状态轮询
  function startStatusPolling() {
    if (statusPollingInterval) clearInterval(statusPollingInterval);
    
    statusPollingInterval = setInterval(() => {
      API.getStatus()
        .then(status => {
          updateSystemStatus(status);
        })
        .catch(err => {
          console.error('获取状态失败:', err);
          // 连接断开时更新状态
          updateSystemStatus({
            system_status: '未连接',
            is_measuring: false
          });
        });
    }, 500); // 每500ms更新一次状态
  }

  // 页面加载完成后初始化
  window.addEventListener('load', () => {
    initChart();
    initEventListeners();
    startStatusPolling();
  });

  // 页面关闭前清理
  window.addEventListener('beforeunload', () => {
    if (statusPollingInterval) {
      clearInterval(statusPollingInterval);
    }
  });
</script>
</body>
</html>